﻿using System;
using System.Collections.Generic;
using Internal.Runtime.Models;
using Internal.Runtime.Services.BattleAttack;
using Runtime.Services.Battle;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleAttack;
using Runtime.Services.BattleSkill;
using UnityEngine;
using UnityEngine.Pool;

namespace Runtime.Models {

    /// <summary>
    /// 进攻方数据
    /// </summary>
    public interface IDFR_BattleAttackSourceModelBase : IDFR_Model, IDFR_BattleEntityModel {

        IDFR_BattleAttackSourceModelBaseSetter AsSetter();

        IDFR_BattleAttacker AsAttacker();

        IDFR_BattleBuffApplier AsBuffApplier();

        IDFR_BattleAttackLookout AsAttackLookout();

        IDFR_BattleEffectTarget AsEffectTarget();

        IDFR_BattleSkillMapPositionProvider AsSkillMapPositionProvider();

        IDFR_BattleAttackBulletProvider AsAttackBulletProvider();

        IDFR_BattleAttackTargetSelector AsAttackTargetSelector();

        /// <summary>
        /// 拥有者玩家ID
        /// </summary>
        DFR_BattlePlayerID OwnerPlayerID { get; }

        /// <summary>
        /// 技能列表
        /// </summary>
        IReadOnlyList<IDFR_BattleSkillModelBase> SkillList { get; }

        /// <summary>
        /// 攻击力
        /// </summary>
        IDFR_ReadOnlyBattleData Attack { get; }

        /// <summary>
        /// 对精英的额外攻击加成
        /// </summary>
        IDFR_ReadOnlyBattleData AttackBossAdditional { get; }

        /// <summary>
        /// 攻击速度
        /// </summary>
        IDFR_ReadOnlyBattleData AttackSpeed { get; }

        /// <summary>
        /// 攻击冷却
        /// </summary>
        IDFR_ReadOnlyBattleData CoolDown { get; }

        /// <summary>
        /// 暴击率
        /// </summary>
        IDFR_ReadOnlyBattleData Critical { get; }

        /// <summary>
        /// 暴击伤害强度
        /// </summary>
        IDFR_ReadOnlyBattleData CriticalPower { get; }

        /// <summary>
        /// 索敌范围
        /// </summary>
        IDFR_ReadOnlyBattleData SpottingRange { get; }

        /// <summary>
        /// 攻击命中方式
        /// </summary>
        DFR_BattleAttackHit AttackHit { get; }

        /// <summary>
        /// 等级
        /// </summary>
        int Level { get; }

        /// <summary>
        /// 攻击目标选择模式
        /// </summary>
        DFR_BattleAttackTargetSelectorMode AttackSelectTargetMode { get; }
    }

    public interface IDFR_BattleAttackSourceModelBaseSetter : IDFR_BattleAttackSourceModelBase {

        /// <summary>
        /// CD
        /// </summary>
        new IDFR_BattleComplexData CoolDown { get; }

        /// <summary>
        /// 攻击速度
        /// </summary>
        new IDFR_BattleComplexData AttackSpeed { get; }

        /// <summary>
        /// 攻击力
        /// </summary>
        new IDFR_BattleComplexData Attack { get; }

        /// <summary>
        /// 对精英的额外攻击加成
        /// </summary>
        new IDFR_BattleComplexData AttackBossAdditional { get; }

        /// <summary>
        /// 暴击率
        /// </summary>
        new IDFR_BattleComplexData Critical { get; }

        /// <summary>
        /// 暴击伤害强度
        /// </summary>
        new IDFR_BattleComplexData CriticalPower { get; }

        /// <summary>
        /// 索敌范围
        /// </summary>
        new IDFR_BattleComplexData SpottingRange { get; }
    }

    public abstract class DFR_BattleAttackSourceModelBase : DFR_Model,
        IDFR_BattleAttackSourceModelBase, IDFR_BattleAttackSourceModelBaseSetter, IDFR_BattleAttackSourceModelBaseInternal,
        IDFR_BattleAttackBulletProvider, IDFR_BattleAttackTargetSelector, IDFR_BattleEffectTarget, IDFR_BattleMapPositionGetter,
        IDFR_BattleAttacker, IDFR_BattleAttackLookout, IDFR_BattleSkillMapPositionProvider, IDFR_BattleBuffApplier {

        public IDFR_BattleAttackSourceModelBaseSetter AsSetter() => this;

        public IDFR_BattleAttacker AsAttacker() => this;

        public IDFR_BattleAttackLookout AsAttackLookout() => this;

        public IDFR_BattleEffectTarget AsEffectTarget() => this;

        public IDFR_BattleSkillMapPositionProvider AsSkillMapPositionProvider() => this;

        public IDFR_BattleBuffApplier AsBuffApplier() => this;

        public IDFR_BattleAttackBulletProvider AsAttackBulletProvider() => this;

        public IDFR_BattleAttackTargetSelector AsAttackTargetSelector() => this;

        DFR_BattleEntityInstanceID IDFR_BattleAttackTargetSelector.EntityInstanceID => EntityInstanceID;

        public DFR_BattleEntityInstanceID EntityInstanceID { get; private set; } = DFR_BattleEntityInstanceID.Empty;

        protected abstract IReadOnlyList<IDFR_BattleSkillModelBase> SkillList { get; }

        private IReadOnlyList<IDFR_BattleSkillModelBase> m_SkillList => SkillList;

        DFR_BattleEntityInstanceID IDFR_BattleAttacker.EntityInstanceID => EntityInstanceID;

        [Autowired]
        private readonly IDFR_BattleComplexData m_CoolDown;
        public IDFR_ReadOnlyBattleData CoolDown => m_CoolDown;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.CoolDown => m_CoolDown;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_AttackSpeed;
        public IDFR_ReadOnlyBattleData AttackSpeed => m_AttackSpeed;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.AttackSpeed => m_AttackSpeed;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.AttackSpeed => m_AttackSpeed;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_Attack;
        public IDFR_ReadOnlyBattleData Attack => m_Attack;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.Attack => m_Attack;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.Attack => m_Attack;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_AttackBossAdditional;
        public IDFR_ReadOnlyBattleData AttackBossAdditional => m_AttackBossAdditional;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.AttackBossAdditional => m_AttackBossAdditional;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.AttackBossAdditional => m_AttackBossAdditional;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_Critical;
        public IDFR_ReadOnlyBattleData Critical => m_Critical;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.Critical => m_Critical;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.Critical => m_Critical;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_CriticalPower;
        public IDFR_ReadOnlyBattleData CriticalPower => m_CriticalPower;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.CriticalPower => m_CriticalPower;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.CriticalPower => m_CriticalPower;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_SpottingRange;
        public IDFR_ReadOnlyBattleData SpottingRange => m_SpottingRange;
        F64 IDFR_BattleAttackLookout.SpottingRange => SpottingRange.Value;
        IDFR_BattleComplexData IDFR_BattleAttackSourceModelBaseSetter.SpottingRange => m_SpottingRange;

        [Autowired]
        private readonly IIntData m_AttackLaunchCount;
        IReadOnlyIntData IDFR_BattleAttacker.LaunchCount => m_AttackLaunchCount;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_DamageHPMax;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.DamageHPMax => m_DamageHPMax;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_DamageHP;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.DamageHP => m_DamageHP;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_Damage;
        IDFR_ReadOnlyBattleData IDFR_BattleAttacker.Damage => m_Damage;

        IEnumerable<IDFR_BattleAttackTarget> IDFR_BattleAttackLookout.Targets => Targets;

        F64 IDFR_BattleAttacker.AttackSpeedFinalFactor => AttackSpeedFinalFactor;

        protected abstract IEnumerable<IDFR_BattleAttackTarget> Targets { get; }

        protected abstract DFR_BattleMapPosition MapPosition { get; }
        DFR_BattleMapPosition IDFR_BattleAttackLookout.MapPosition => MapPosition;
        DFR_BattleMapPosition IDFR_BattleAttacker.MapPosition => MapPosition;
        DFR_BattleMapPosition IDFR_BattleSkillMapPositionProvider.MapPosition => MapPosition;
        DFR_BattleMapPosition IDFR_BattleMapPositionGetter.MapPosition => MapPosition;

        protected abstract F64 AttackSpeedFinalFactor { get; }

        public DFR_BattleAttackHit AttackHit { get; protected set; }

        public DFR_BattlePlayerID OwnerPlayerID { get; private set; } = DFR_BattlePlayerID.None;

        DFR_BattleMapPosition IDFR_BattleAttackTargetSelector.MapPosition => MapPosition;

        public DFR_BattleAttackTargetSelectorMode AttackSelectTargetMode { get; protected set; }
        DFR_BattleAttackTargetSelectorMode IDFR_BattleAttackTargetSelector.Mode => AttackSelectTargetMode;

        protected abstract int TargetNumber { get; }

        protected abstract F64 BulletFlySpeed { get; }

        F64 IDFR_BattleAttackBulletProvider.BulletFlySpeed => BulletFlySpeed;

        protected abstract string BulletFlyAssetKey { get; }

        string IDFR_BattleAttackBulletProvider.BulletFlyAssetKey => BulletFlyAssetKey;

        protected abstract string BulletHitAssetKey { get; }

        string IDFR_BattleAttackBulletProvider.BulletHitAssetKey => BulletHitAssetKey;

        int IDFR_BattleAttackTargetSelector.Number => TargetNumber;

        IReadOnlyList<IDFR_BattleSkillModelBase> IDFR_BattleAttackSourceModelBase.SkillList => m_SkillList;

        IEnumerable<IDFR_BattleBuffProvider> IDFR_BattleBuffApplier.BuffProviders => m_BuffProviderSet;
        private HashSet<IDFR_BattleBuffProvider> m_BuffProviderSet = new();

        public int Level { get; private set; }

        bool IDFR_BattleEffectTarget.IsEnabled => IsEnabled;
        protected virtual bool IsEnabled => true;

        protected override void Dispose() {
            (BattleAttackService.Instance as IDFR_BattleAttackServiceInternal).ReleaseFocus(EntityInstanceID);
            EntityInstanceID = DFR_BattleEntityInstanceID.Empty;
            OwnerPlayerID = DFR_BattlePlayerID.None;
            foreach (var buffProvider in m_BuffProviderSet) {
                if (buffProvider is IDFR_BattleEffectHolder effectHolder) {
                    BattleServiceBase.Instance.DetachHolder(effectHolder.EntityHandle);
                }
            }
            m_BuffProviderSet = null;
            base.Dispose();
        }

        protected abstract bool Initialize();

        void IDFR_BattleEntityModelInternal.Initialize(DFR_BattleEntityInstanceID instanceID) {
            EditBegin();
            EntityInstanceID = instanceID;
            m_CoolDown.Initialize(F64.Zero, F64.One, F64.Zero);
            EditDone();
        }

        void IDFR_BattleAttackSourceModelBaseInternal.Initialize(DFR_BattlePlayerID ownerPlayerID, int level) {
            level = Mathf.Max(level, 1);
            EditBegin();
            OwnerPlayerID = ownerPlayerID;
            Level = level;
            if (Initialize()) {
            }
            EditDone();
        }

        void IDFR_BattleBuffApplier.AddBuff(IDFR_BattleBuffProvider buffProvider) {
            m_BuffProviderSet.Add(buffProvider);

            m_DamageHPMax.Base.Add(buffProvider.DamageHPMaxBase);
            m_DamageHPMax.Factor.Add(buffProvider.DamageHPMaxFactor);
            m_DamageHPMax.Additional.Add(buffProvider.DamageHPMaxAdditional);
            m_DamageHP.Base.Add(buffProvider.DamageHPBase);
            m_DamageHP.Factor.Add(buffProvider.DamageHPFactor);
            m_DamageHP.Additional.Add(buffProvider.DamageHPAdditional);
            m_Damage.Base.Add(buffProvider.DamageBase);
            m_Damage.Factor.Add(buffProvider.DamageFactor);
            m_Damage.Additional.Add(buffProvider.DamageAdditional);
            m_Attack.Base.Add(buffProvider.AttackBase);
            m_Attack.Factor.Add(buffProvider.AttackFactor);
            m_Attack.Additional.Add(buffProvider.AttackAdditional);
            m_AttackBossAdditional.Base.Add(buffProvider.AttackBossAdditionalBase);
            m_AttackBossAdditional.Factor.Add(buffProvider.AttackBossAdditionalFactor);
            m_AttackBossAdditional.Additional.Add(buffProvider.AttackBossAdditionalAdditional);
            m_AttackSpeed.Base.Add(buffProvider.AttackSpeedBase);
            m_AttackSpeed.Factor.Add(buffProvider.AttackSpeedFactor);
            m_AttackSpeed.Additional.Add(buffProvider.AttackSpeedAdditional);
            m_Critical.Base.Add(buffProvider.CriticalBase);
            m_Critical.Factor.Add(buffProvider.CriticalFactor);
            m_Critical.Additional.Add(buffProvider.CriticalAdditional);
            m_CriticalPower.Base.Add(buffProvider.CriticalPowerBase);
            m_CriticalPower.Factor.Add(buffProvider.CriticalPowerFactor);
            m_CriticalPower.Additional.Add(buffProvider.CriticalPowerAdditional);
            m_SpottingRange.Base.Add(buffProvider.SpottingRangeBase);
            m_SpottingRange.Factor.Add(buffProvider.SpottingRangeFactor);
            m_SpottingRange.Additional.Add(buffProvider.SpottingRangeAdditional);

            if (buffProvider is IDFR_BattleEffectHolder effectHolder && effectHolder.HasModelAsset) {
                BattleServiceBase.Instance.AttachHolder(effectHolder, MapPosition);
            }
        }

        void IDFR_BattleBuffApplier.RemoveBuff(IDFR_BattleBuffProvider buffProvider) => RemoveBuff(buffProvider);
        private void RemoveBuff(IDFR_BattleBuffProvider buffProvider) {
            m_BuffProviderSet.Remove(buffProvider);

            m_DamageHPMax.Base.Remove(buffProvider.DamageHPMaxBase);
            m_DamageHPMax.Factor.Remove(buffProvider.DamageHPMaxFactor);
            m_DamageHPMax.Additional.Remove(buffProvider.DamageHPMaxAdditional);
            m_DamageHP.Base.Remove(buffProvider.DamageHPBase);
            m_DamageHP.Factor.Remove(buffProvider.DamageHPFactor);
            m_DamageHP.Additional.Remove(buffProvider.DamageHPAdditional);
            m_Damage.Base.Remove(buffProvider.DamageBase);
            m_Damage.Factor.Remove(buffProvider.DamageFactor);
            m_Damage.Additional.Remove(buffProvider.DamageAdditional);
            m_Attack.Base.Remove(buffProvider.AttackBase);
            m_Attack.Factor.Remove(buffProvider.AttackFactor);
            m_Attack.Additional.Remove(buffProvider.AttackAdditional);
            m_AttackBossAdditional.Base.Remove(buffProvider.AttackBossAdditionalBase);
            m_AttackBossAdditional.Factor.Remove(buffProvider.AttackBossAdditionalFactor);
            m_AttackBossAdditional.Additional.Remove(buffProvider.AttackBossAdditionalAdditional);
            m_AttackSpeed.Base.Remove(buffProvider.AttackSpeedBase);
            m_AttackSpeed.Factor.Remove(buffProvider.AttackSpeedFactor);
            m_AttackSpeed.Additional.Remove(buffProvider.AttackSpeedAdditional);
            m_Critical.Base.Remove(buffProvider.CriticalBase);
            m_Critical.Factor.Remove(buffProvider.CriticalFactor);
            m_Critical.Additional.Remove(buffProvider.CriticalAdditional);
            m_CriticalPower.Base.Remove(buffProvider.CriticalPowerBase);
            m_CriticalPower.Factor.Remove(buffProvider.CriticalPowerFactor);
            m_CriticalPower.Additional.Remove(buffProvider.CriticalPowerAdditional);
            m_SpottingRange.Base.Remove(buffProvider.SpottingRangeBase);
            m_SpottingRange.Factor.Remove(buffProvider.SpottingRangeFactor);
            m_SpottingRange.Additional.Remove(buffProvider.SpottingRangeAdditional);

            if (buffProvider is IDFR_BattleEffectHolder effectHolder) {
                BattleServiceBase.Instance.DetachHolder(effectHolder.EntityHandle);
            }
        }

        void IDFR_BattleBuffApplier.RemoveBuff(DFR_BattleEntityID effectEntityID, Action<IDFR_BattleBuffProvider> onRemove) {
            var removingSet = HashSetPool<IDFR_BattleBuffProvider>.Get();
            foreach (var buffProvider in m_BuffProviderSet) {
                if (buffProvider.EntityInstanceID.ID == effectEntityID) {
                    removingSet.Add(buffProvider);
                }
            }
            foreach (var buffProvider in removingSet) {
                RemoveBuff(buffProvider);
                onRemove?.Invoke(buffProvider);
            }
            HashSetPool<IDFR_BattleBuffProvider>.Release(removingSet);
        }

        void IDFR_BattleBuffApplier.SyncBuffPositionOnce() {
            foreach (var buffProvider in m_BuffProviderSet) {
                if (buffProvider is IDFR_BattleEffectHolder effectHolder) {
                    effectHolder.AsSetter().SyncPositionOnce(EntityInstanceID);
                }
            }
        }
    }
}


namespace Internal.Runtime.Models {

    public interface IDFR_BattleAttackSourceModelBaseInternal : IDFR_BattleEntityModelInternal {

        void Initialize(DFR_BattlePlayerID ownerPlayerID, int level);
    }
}